#ifndef __PIXELBYPIXEL_H
#define __PIXELBYPIXEL_H

#include "stdstratego.h"
#include "stdsc.h"
#include "linebyline.h"

void pixelbypixel(argcode_t *pbp_argcode, int pbp_arguments, code pbp_prologue, code pbp_body, code pbp_epilogue)
{
  int pbp_ii, pbp_fi=-1;
  int pbp_stride;
  code mybody;
  
  mybody = reduce(pbp_body);

  for (pbp_ii=0; pbp_ii < pbp_arguments; pbp_ii++)
  {
    if (pbp_argcode[pbp_ii].argtype == ARG_STREAM_IN || pbp_argcode[pbp_ii].argtype == ARG_STREAM_OUT)
    {
      /* Adjust first input */
      if (pbp_argcode[pbp_ii].argtype == ARG_STREAM_IN)
        if (pbp_fi == -1)
  	  pbp_fi = pbp_ii;
    
      @declare1d(addrpointer(pbp_argcode[pbp_ii].datatype), pbp_argcode[pbp_ii].id, 1);

      mybody = replace(pbp_argcode[pbp_ii].id,
  		        replace(`id`, pbp_argcode[pbp_ii].id, `&id[0][pbp_ii]`),
		        mybody);
    }
    else
    {
      /* Non-streams must be initialised */
      @declare(addrpointer(pbp_argcode[pbp_ii].datatype), pbp_argcode[pbp_ii].id);
      
      if (@dataclass(pbp_argcode[pbp_ii].datatype) == DATACLASS_INTEGER)
        @pbp_argcode[pbp_ii].id = &(@pbp_argcode[pbp_ii].argid).data.d;
      else if (@dataclass(pbp_argcode[pbp_ii].datatype) == DATACLASS_FLOAT)
        @pbp_argcode[pbp_ii].id = &(@pbp_argcode[pbp_ii].argid).data.f;
       else
        @pbp_argcode[pbp_ii].id = @cast(addpointer(pbp_argcode[pbp_ii].datatype), (@pbp_argcode[pbp_ii].argid).data.b);
    }

    pbp_argcode[pbp_ii].state.buffer = 1;
    pbp_argcode[pbp_ii].state.state = 1;
    pbp_argcode[pbp_ii].state.delay = 0;
  }
	
  pbp_stride = BufferGetStride(pbp_fi);

  prologue {
    $@pbp_prologue;
  };
  
  repeat {
    int pbp_ii;
    
    #pragma TCS_unroll=16
    for (pbp_ii=0; pbp_ii < pbp_stride; pbp_ii++)
      $@mybody;
  };
                        
  epilogue {
    $@pbp_epilogue;
  };
}

#endif /* __PIXELBYPIXEL_H */
